import java.awt.Color;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;

import javax.swing.JComponent;


public class Creature {
	
	private static final  float distanceEnemy = 6.0f;
	private static final  float distanceMate = 3.0f;
	private static final float distanceEating = 3.0f;
	private static final float maxSpeed = 1.0f;
	private static final float perception = 15.0f;
	private static final int maxStrength = 100;
	private static final int maxDefense = 100;
	private static final int needStrength = 80;
	
	private ArrayList<Creature> mates;
	private ArrayList<Creature> neighbours;
	private ArrayList<Creature> enemies;
	private ArrayList<Creature> prey;
	
	float x;
	float y;
	float dx;
	float dy;
	
	private boolean alive;
	public boolean justCreated;
	private int creatureStrength;
	private int creatureStartingStrength;
	private int creatureDefense;
	private int creatureStartingDefense;
	private int defense;
	private int age;
	
	private int fitness;
	private float creatureSpeed;
	private float creatureMaxSpeed;
	private float creatureDistanceEating;
	private float creaturePerception;
	private float creatureDistanceMate;
	private float creatureDistanceEnemy;
	private int maxAge;
	private int matingCycle;
	private int matingAge;
	
	private String chromosome;
	
	private int numMatesSeen;
	private Creature nearestMate;
	private float distanceNearestMate;
	
	private int numEnemiesSeen;
	private Creature nearestEnemy;
	private float distanceNearestEnemy;
	
	private int numPreySeen;
	private Creature nearestPrey;
	private float distanceNearestPrey;
	
	private int numFoodSeen;
	private Nutrient nearestFood;
	private float distanceNearestFood;
	
	private Color color;
	
	private int type;
	private int myPrey;
	private int myPredator;
	
	public Creature() {
		this.x = (float) (Math.random() * Simulation.WORLD_WIDTH);
		this.y = (float) (Math.random() * Simulation.WORLD_HEIGTH);
		alive = true;
		age = 0;
		
		
		creatureMaxSpeed = (float) (maxSpeed + (Math.random() * 0.5f));
		creatureDistanceEating = (float) (distanceEating + (Math.random() * 0.5f));
		creaturePerception = (float) (perception + (Math.random() * 0.5f));
		creatureDistanceMate = (float) (distanceMate + (Math.random() * 0.5f));
		creatureDistanceEnemy = (float) (distanceEnemy + (Math.random() * 0.5f));
		creatureStrength = creatureStartingStrength = (int) ((Math.random() * (maxStrength + 1)));
		creatureDefense = creatureStartingDefense = (int) ((Math.random() * (maxDefense + 1)));
		maxAge = (int) (10 + Math.random() * (100 - 10) + 1);
		matingCycle = 0;
		getFitness();
		
		
		dx = (float) (Math.random() * Simulation.WORLD_WIDTH) / 2;
		dy = (float) (Math.random() * Simulation.WORLD_HEIGTH) / 2;
		creatureSpeed = (float) Math.sqrt(((dx) * (dx))
				+ ((dy) * (dy)));
		
		numMatesSeen = 0;
		nearestMate = null;
		distanceNearestMate = Float.POSITIVE_INFINITY;

		numEnemiesSeen = 0;
		nearestEnemy = null;
		distanceNearestEnemy = Float.POSITIVE_INFINITY;
		
		numPreySeen = 0;
		nearestPrey = null;
		distanceNearestPrey = Float.POSITIVE_INFINITY;
		
		numFoodSeen = 0;
		nearestFood = null;
		distanceNearestFood = Float.POSITIVE_INFINITY;
		
		mates = new ArrayList<Creature>();
		neighbours = new ArrayList<Creature>();
		enemies = new ArrayList<Creature>();
		prey = new ArrayList<Creature>();
		justCreated = true;
	}
	
	public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }
    
    public float getDistanceNearestEnemy() {
    	return distanceNearestEnemy;
    }
    
    public void setDistanceNearestEnemy(float distanceNearestEnemy) {
    	this.distanceNearestEnemy = distanceNearestEnemy;
    }
    
    public void setX(float x) {
        this.x = x;
    }

    public void setY(float y) {
    	this.y = y;
    }
    
    public float getDX() {
        return dx;
    }

    public float getDY() {
        return dy;
    }
    
    public void setDX(float dx) {
        this.dx = dx;
    }

    public void setDY(float dy) {
    	this.dy = dy;
    }

	public boolean isAlive() {
    	return alive;
    }
	
	public int getFitness() {
		fitness = (int) ((creatureStrength) + (creatureDefense));
		return fitness;
	}

	public String getChromosome() {
		return chromosome;
	}

	public void setChromosome(String chromosome) {
		this.chromosome = chromosome;
	}
	
	public float getPerception() {
		return perception;
	}

	public void clearMatesList() {
		neighbours.clear();
		
		numMatesSeen = 0;
		nearestMate = null;
		distanceNearestMate = Float.POSITIVE_INFINITY;
	}

	public void addToNeighboursList(Creature c) {
		neighbours.add(c);
		numMatesSeen++;
	}
	
	public void addToCommunity(Creature c) {
		mates.add(c);
	}
	
	public void addToEnemyList(Creature c) {
		enemies.add(c);	
	}
	
	public void addToPreyList(Creature c) {
		prey.add(c);	
	}

	public float getDistanceNearestMate() {
		return distanceNearestMate;
	}

	public void setDistanceNearestMate(float distanceNearestMate) {
		this.distanceNearestMate = distanceNearestMate;
	}

	public void setNearestFlockMate(Creature c) {
		this.nearestMate = c;
	}
	
	public Creature getNearestMate() {
		return nearestMate;
	}
	
	public int getNumberMates() {
		return numMatesSeen;
	}

	public ArrayList<Creature> getMates() {
		return mates;
	}
	
	public ArrayList<Creature> getEnemies() {
		return enemies;
	}
	
	public ArrayList<Creature> getFood() {
		return prey;
	}

	public Creature getMate(int i) {
		Creature mate = (Creature) mates.get(i);
		return mate;
	}
	
	public Creature getNeighbour(int i) {
		Creature nearestMate = (Creature) neighbours.get(i);
		return nearestMate;
	}
	
	public Creature getEnemy(int i) {
		Creature enemy = (Creature) enemies.get(i);
		return enemy;
	}
	
	public Creature getFood(int i) {
		Creature food = (Creature) prey.get(i);
		return food;
	}

	public void incrementMatingCycle() {
		matingCycle++;
	}

	public void resetMatingCycle() {
		matingCycle = 0;
	}

	public void setType(int type) {
		this.type = type;
	}

	public void setPrey(int myPrey) {
		this.myPrey = myPrey;
	}

	public void setPredator(int myPredator) {
		this.myPredator = myPredator;
	}

	public int getType() {
		return type;
	}

	public void increaseDefense(int increase) {
		creatureDefense += increase;
	}
	
	public void decreaseDefense(int decrease) {
		creatureDefense -= decrease;
	}

	public void setNumberEnemiesSeen(int numEnemiesSeen) {
		this.numEnemiesSeen = numEnemiesSeen;
	}

	public void setNearestEnemy(Creature c) {
		this.nearestEnemy = c;
	}
	
	public Creature getNearestEnemy() {
		return nearestEnemy;
	}

	public void increaseEnemiesSeen() {
		numEnemiesSeen++;
	}

	public int getEnemiesSeen() {
		return numEnemiesSeen;
	}

	public int getStrength() {
		return creatureStrength;
	}

	public int getPrey() {
		return myPrey;
	}

	public void setNumberPreySeen(int numPreySeen) {
		this.numPreySeen = numPreySeen;
	}

	public void setNearestPrey(Creature nearestPrey) {
		this.nearestPrey = nearestPrey;
	}

	public void setDistanceNearestPrey(float positiveInfinity) {
		this.distanceNearestPrey = positiveInfinity;
	}
	
	public void setNumberFoodSeen(int numFoodSeen) {
		this.numFoodSeen = numFoodSeen;
	}

	public void setNearestFood(Nutrient nearestFood) {
		this.nearestFood = nearestFood;
	}

	public void setDistanceNearestFood(float distanceNearestFood) {
		this.distanceNearestFood = distanceNearestFood;
	}

	public void increasePreySeen() {
		numPreySeen++;
	}
	
	public void increaseFoodSeen() {
		numFoodSeen++;	
	}

	public float getDistanceNearestPrey() {
		return distanceNearestPrey;
	}

	public int getPreySeen() {
		return numPreySeen;
	}

	public float getMaxSpeed() {
		return maxSpeed;
	}

	public Creature getNearestPrey() {
		return nearestPrey;
	}

	public void increaseStrength() {
		creatureStrength++;
	}

	public void setAlive(boolean alive) {
		this.alive = alive;
	}

	public void decreaseStrength() {
		creatureStrength--;
	}

	public int getDefense() {
		return creatureDefense;
	}

	public int getMaxAge() {
		return maxAge;
	}

	public boolean isFriend(Creature c) {
		if ((this.getStrength() > 0) && (this.getStrength() <= 20)) {
			if ((c.getStrength() > 0) && (c.getStrength() <= 20)) {
				return true;
			}
		}
		else if ((this.getStrength() > 20) && (this.getStrength() <= 40)) {
			if ((c.getStrength() > 20) && (c.getStrength() <= 40)) {
				return true;
			}
		}
		else if ((this.getStrength() > 40) && (this.getStrength() <= 60)) {
			if ((c.getStrength() > 40) && (c.getStrength() <= 60)) {
				return true;
			}
		}
		else if ((this.getStrength() > 60) && (this.getStrength() <= 80)) {
			if ((c.getStrength() > 60) && (c.getStrength() <= 80)) {
				return true;
			}
		}
		else if ((this.getStrength() > 80) && (this.getStrength() <= 100)) {
			if ((c.getStrength() > 80) && (c.getStrength() <= 100)) {
				return true;
			}
		}
		return false;
	}
	
	public boolean isPredator(Creature c) {
		if ((this.getStrength() > 0) && (this.getStrength() <= 20) &&
				(c.getStrength() > 20)) {
					return true;
				}
		else if ((this.getStrength() > 20) && (this.getStrength() <= 40) &&
				(c.getStrength() > 40)) {
					return true;
				}
		else if ((this.getStrength() > 40) && (this.getStrength() <= 60) &&
				(c.getStrength() > 60)) {
					return true;
				}
		else if ((this.getStrength() > 60) && (this.getStrength() <= 80) &&
				(c.getStrength() > 80)) {
					return true;
				}
		else {
			return false;
		}
	}
	
	public boolean isPrey(Creature c) {
		if ((this.getStrength() > 20) && (this.getStrength() <= 40) &&
				(c.getStrength() <= 20)) {
					return true;
				}
		else if ((this.getStrength() > 40) && (this.getStrength() <= 60) &&
				(c.getStrength() <= 40)) {
					return true;
				}
		else if ((this.getStrength() > 60) && (this.getStrength() <= 80) &&
				(c.getStrength() <= 60)) {
					return true;
				}
		else if ((this.getStrength() > 80) && (this.getStrength() <= 100) &&
				(c.getStrength() <= 80)) {
					return true;
				}
		else {
			return false;
		}
	}

	public boolean containsInCommunity(Creature c) {
		if (this.getMates().contains(c)) {
			return true;
		}
		else {
			return false;
		}
	}

	public boolean containsInEnemyList(Creature c) {
		if (this.getEnemies().contains(c)) {
			return true;
		}
		else {
			return false;
		}
	}

	public boolean containsInPreyList(Creature c) {
		if (this.getFood().contains(c)) {
			return true;
		}
		else {
			return false;
		}
	}

	public float getDistanceNearestFood() {
		return distanceNearestFood;
	}

	public int getNumFoodSeen() {
		return numFoodSeen;
	}

	public Nutrient getNearestFood() {
		return nearestFood;
	}

	public int getMatingCycle() {
		return matingCycle;
	}

	public void setStrength(int creatureStrength) {
		this.creatureStrength = creatureStrength;
	}

	public void setDefense(int defense) {
		this.creatureDefense = defense;
	}

	public void setMates(Creature c1) {
		for (int i = 0; i < c1.getMates().size(); i++) {
			mates.add(c1.getMate(i));
		}
	}

	public void setEnemies(Creature c1) {
		for (int i = 0; i < c1.getEnemies().size(); i++) {
			enemies.add(c1.getEnemy(i));
		}
	}

	public void setFood(Creature c1) {
		for (int i = 0; i < c1.getFood().size(); i++) {
			prey.add(c1.getFood(i));
		}
	}

	public float getSpeed() {
		creatureSpeed = (float) Math.sqrt(((dx) * (dx))
				+ ((dy) * (dy)));
		return creatureSpeed;
	}

	public void setSpeed(float creatureSpeed) {
		this.creatureSpeed = creatureSpeed;
	}

	public void increaseAge() {
		age++;
	}

	public float getAge() {
		return age;
	}

	public boolean isJustCreated() {
		return justCreated;
	}

	public void removeMate(int i) {
		mates.remove(i);
	}

	public void removeEnemy(int i) {
		enemies.remove(i);
	}

	public void removePrey(int i) {
		prey.remove(i);
	}

	public void setJustCreated(boolean justCreated) {
		this.justCreated = justCreated;
	}
}